package han.proof;

import com.han.http.client.exception.NullContentMatchedException;
import com.han.http.client.exception.RequestNotExecutedException;
import com.han.http.client.method.BaseHttpRequest;
import com.han.http.client.method.HttpGet;
import com.han.http.client.paramter.RequestHeader;
import com.han.http.util.Regex;
import han.exception.NullQrCookieException;
import han.exception.NullSetCookieException;
import han.exception.QrCodeOverdueException;
import han.util.QqUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author: Han
 * @date: 2018/7/18 13:19
 * @dscription: QQ群官网类
 */
public class GroupWebsiteLogin {

    private static String loginCookie;
    private static int bkn;
    /**
     * 线程池对象
     */
    private ExecutorService executorService;
    /**
     * cookieMap
     */
    private Map<String, String> cookieMap;
    /**
     * 链接Map
     */
    private Map<String, String> urlMap;
    /**
     * 弹出框对象
     */
    private QrPopupBox qrPopupBox;

    /**
     * 日志
     */
    private static Logger logger = LoggerFactory.getLogger(GroupWebsiteLogin.class);

    public GroupWebsiteLogin() {
        urlMap = new HashMap<>();
        cookieMap = new HashMap<>();
        executorService = Executors.newSingleThreadExecutor();
    }

    /**
     * 获取bkn
     *
     * @return bkn
     */
    public static int getBkn() {
        return bkn;
    }

    /**
     * 获取登录cookie
     *
     * @return 登录cookie
     */
    public static String getLoginCookie() {
        return loginCookie;
    }

    /**
     * 使用通用配置,指定url和请求头,使用get方法获取Response Headers中的set-cookie,并拼接
     *
     * @param urlStr         url
     * @param requestHeaders 请求头
     */
    private boolean getCookies(String urlStr, RequestHeader[] requestHeaders, boolean isRedirect) throws
            NullSetCookieException, QrCodeOverdueException {

        String[] qrCodeStatus = {
                "二维码已失效。",
                "二维码认证中。",
                "二维码未失效。"
        };
        boolean isGot = false;
        int generalTimeout = 20;
        Map<String, List<String>> tempMap = new LinkedHashMap<>();
        HttpGet httpGet = BaseHttpRequest.getGetMethod(urlStr);
        httpGet.setConnectTimeout(1000 * generalTimeout);
        httpGet.setReadTimeout(1000 * generalTimeout);
        httpGet.setHeaders(requestHeaders);
        httpGet.setRedirects(isRedirect);
        try {
            httpGet.execute();
            tempMap.putAll(httpGet.getHeaderFields());
        } catch (IOException | RequestNotExecutedException e) {
            logger.info(e.toString());
            StackTraceElement[] stackTraceElements = e.getStackTrace();
            for (StackTraceElement stackTraceElement : stackTraceElements) {
                logger.error(stackTraceElement.toString());
            }
        }
        try {
            String text = httpGet.getText();
            tempMap.put("Page-Content", Collections.singletonList(text));
            if (text.contains(qrCodeStatus[0])) {
                throw new QrCodeOverdueException();
            }
        } catch (RequestNotExecutedException | IOException e) {
            logger.info(e.toString());
            StackTraceElement[] stackTraceElements = e.getStackTrace();
            for (StackTraceElement stackTraceElement : stackTraceElements) {
                logger.error(stackTraceElement.toString());
            }
        }
        try {
            List<String> cookieList = tempMap.get("Set-Cookie");
            if (Objects.isNull(cookieList) || cookieList.isEmpty()) {
                throw new NullSetCookieException();
            }
            //获取cookie放入cookieMap中
            for (String tempStr : cookieList) {
                //去掉多余的字符串
                String tempCookie = Regex.matchString(tempStr, "((?!;).)*");
                fillCookieMap(tempCookie);
            }
            List<String> pageList = tempMap.get("Page-Content");
            if (!Objects.isNull(pageList) && !pageList.isEmpty()) {
                try {
                    //找出确认扫码返回的url
                    String aimedUrl = Regex.matchString(pageList.get(0), "http[s]{0,1}://ptlogin2.qun.qq.com/check_sig((?!',).)*");
                    urlMap.put("CheckSigUrl", aimedUrl);
                } catch (NullContentMatchedException ignore) {
                }
            }
            isGot = true;
        } catch (NullSetCookieException e) {
            throw e;
        } catch (Exception e) {
            logger.info(e.toString());
            StackTraceElement[] stackTraceElements = e.getStackTrace();
            for (StackTraceElement stackTraceElement : stackTraceElements) {
                logger.error(stackTraceElement.toString());
            }
        }

        return isGot;
    }

    public void login() throws Exception {
        //xlogin
        String parameter = "appid=715030901&daid=73&hide_close_icon=1&pt_no_auth=1&s_url=https%3A%2F%2Fqun.qq.com%2Fmember.html";
        String firstUrlStr = "https://xui.ptlogin2.qq.com/cgi-bin/xlogin?" + parameter;
        RequestHeader[] firstRequestHeaders = {
                new RequestHeader("%3Aauthority", "xui.ptlogin2.qq.com"),
                new RequestHeader("%3Amethod", "GET"),
                new RequestHeader("%3Apath", "/cgi-bin/xlogin?" + parameter),
                new RequestHeader("%3Ascheme", "https"),
                new RequestHeader("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"),
                new RequestHeader("accept-encoding", "gzip, deflate, br"),
                new RequestHeader("accept-language", "zh-CN,zh;q=0.9"),
                new RequestHeader("referer", "https://qun.qq.com/member.html"),
                new RequestHeader("upgrade-insecure-requests", "1"),
                new RequestHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36")
        };
        //获取初始cookie放入map中
        getCookies(firstUrlStr, firstRequestHeaders, true);

        //ptqrshow
        //获取二维码和其cookie并放入map中
        StringBuilder tempCookieSB = new StringBuilder();
        String key = "pt_login_sig";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "pt_clientip";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "pt_serverip";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "pt_local_token";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "uikey";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "pt_guid_sig";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        //获取二维码并显示
        scanQRCode(tempCookieSB.toString());

        //不断发送校验请求,直到返回cookie
        tempCookieSB = new StringBuilder();
        String ptLoginSig;
        key = "pt_login_sig";
        ptLoginSig = cookieMap.get(key);
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "pt_clientip";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "pt_serverip";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "pt_local_token";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "uikey";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "pt_guid_sig";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        tempCookieSB.append("pgv_pvi=8338422784; pgv_si=s7454607360;");
        key = "qrsig";
        String qrsig = cookieMap.get("qrsig");
        tempCookieSB.append(key).append("=").append(qrsig).append("; ");
        String actionStr = "0-0-" + System.currentTimeMillis();
        parameter = "u1=https%3A%2F%2Fqun.qq.com%2Fmember.html" +
                "&ptqrtoken=" + QqUtils.hash3(qrsig) +
                "&ptredirect=1&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=" + actionStr +
                "&js_ver=10276&js_type=1&login_sig=" + ptLoginSig +
                "&pt_uistyle=40&aid=715030901&daid=73&";
        String ptqrUrlStr = "https://ssl.ptlogin2.qq.com/ptqrlogin?" + parameter;
        RequestHeader[] ptqrHeaders = {
                new RequestHeader("%0aauthority", "ssl.ptlogin2.qq.com"),
                new RequestHeader("%0amethod", "GET"),
                new RequestHeader("%0apath", "/ptqrlogin?" + parameter),
                new RequestHeader("%0ascheme", "https"),
                new RequestHeader("accept", "*/*"),
                new RequestHeader("accept-encoding", "gzip, deflate, br"),
                new RequestHeader("accept-language", "zh-CN,zh;q=0.9"),
                new RequestHeader("cookie", tempCookieSB.toString()),
                new RequestHeader("referer", "https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=715030901&daid=73&hide_close_icon=1&pt_no_auth=1&s_url=https%3A%2F%2Fqun.qq.com%2Fmember.html"),
                new RequestHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36")
        };
        boolean isGot = false;
        while (!isGot) {
            try {
                isGot = getCookies(ptqrUrlStr, ptqrHeaders, true);
            } catch (QrCodeOverdueException e) {
                JOptionPane.showMessageDialog(null, "二维码已过期,请重启程序", "提示", JOptionPane.ERROR_MESSAGE);
                System.exit(0);
            } catch (NullSetCookieException ignore) {
            } catch (Exception e) {
                logger.info(e.toString());
                StackTraceElement[] stackTraceElements = e.getStackTrace();
                for (StackTraceElement stackTraceElement : stackTraceElements) {
                    logger.error(stackTraceElement.toString());
                }
            }
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //关闭弹窗
        qrPopupBox.dispose();
        executorService.shutdown();

        tempCookieSB = new StringBuilder();
        tempCookieSB.append("pgv_pvi=8338422784; pgv_si=s7454607360;");
        key = "pt2gguin";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "uin";
        String uin = cookieMap.get(key);
        tempCookieSB.append(key).append("=").append(uin).append("; ");
        key = "skey";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "ptisp";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "RK";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        key = "ptcz";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append("; ");
        String checkUrlStr = urlMap.get("CheckSigUrl");
        RequestHeader[] checkHeaders = {
                new RequestHeader("Host", "ptlogin2.web2.qq.com"),
                new RequestHeader("Connection", "keep-alive"),
                new RequestHeader("Upgrade-Insecure-Requests", "1"),
                new RequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36"),
                new RequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"),
                new RequestHeader("Accept-Encoding", "gzip, deflate"),
                new RequestHeader("Accept-Language", "zh-CN,zh;q=0.9"),
                new RequestHeader("Cookie", tempCookieSB.toString())
        };
        getCookies(checkUrlStr, checkHeaders, false);

        tempCookieSB = new StringBuilder();
        key = "pgv_pvi";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append(";");
        key = "pt2gguin";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append(";");
        key = "RK";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append(";");
        key = "ptcz";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append(";");
        key = "_qpsvr_localtk";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append(";");
        key = "pgv_si";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append(";");
        key = "uin";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append(";");
        key = "skey";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append(";");
        key = "ptisp";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append(";");
        key = "p_uin";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append(";");
        key = "pt4_token";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append(";");
        key = "p_skey";
        tempCookieSB.append(key).append("=").append(cookieMap.get(key)).append(";");
        loginCookie = tempCookieSB.toString();

        bkn = QqUtils.bkn(cookieMap.get("skey"));
    }

    /**
     * 将字符串形式的cookie分开,以键值对形式存储
     *
     * @param cookie 字符串形式的cookie
     */
    private void fillCookieMap(String cookie) {

        //分割成键值对
        String[] cookies = cookie.split("=");

        if (cookies.length == 2) {
            //放入
            cookieMap.put(cookies[0], cookies[1]);
        } else {
            //如果没有分成键值对,加入单个cookie并以英文分号隔开
            String c = cookieMap.get("SingleCookie");
            if (Objects.isNull(c)) {
                c = "";
            }
            c = c + cookie + ";";
            cookieMap.put("SingleCookie", c);
        }
    }

    /**
     * 发送请求获取二维码,弹出
     *
     * @param cookie cookie
     * @throws NullQrCookieException 没有二维码
     */
    private void scanQRCode(String cookie) throws NullQrCookieException {

        String qrCookie = null;

        //获取二维码cookie和二维码
        String parameter = "appid=715030901&e=2&l=M&s=3&d=72&v=4&t=" + Math.random() + "&daid=73&pt_3rd_aid=0";
        String urlStr = "https://ssl.ptlogin2.qq.com/ptqrshow?" + parameter;
        RequestHeader[] headers = {
                new RequestHeader("%3Aauthority", "ssl.ptlogin2.qq.com"),
                new RequestHeader("%3Amethod", "GET"),
                new RequestHeader("%3Apath", "/ptqrshow?" + parameter),
                new RequestHeader("%3Ascheme", "https"),
                new RequestHeader("accept", "image/webp,image/apng,image/*,*/*;q=0.8"),
                new RequestHeader("accept-encoding", "gzip, deflate, br"),
                new RequestHeader("accept-language", "zh-CN,zh;q=0.9"),
                new RequestHeader("referer", "https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=715030901&daid=73&hide_close_icon=1&pt_no_auth=1&s_url=https%3A%2F%2Fqun.qq.com%2Fmember.html"),
                new RequestHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML," +
                        " like Gecko) Chrome/67.0.3396.87 Safari/537.36"),
                new RequestHeader("cookie", cookie)
        };
        int generalTimeout = 1000 * 20;
        Icon icon = null;
        byte[] imageBytes;
        HttpGet httpGet = BaseHttpRequest.getGetMethod(urlStr);
        httpGet.setConnectTimeout(1000 * generalTimeout);
        httpGet.setReadTimeout(1000 * generalTimeout);
        httpGet.setHeaders(headers);
        try {
            httpGet.execute();
            imageBytes = httpGet.getBytes();
            icon = new ImageIcon(imageBytes);
            qrCookie = httpGet.getHeaderField("set-cookie");
            qrCookie = Regex.matchString(qrCookie, "((?!;).)*");
            fillCookieMap(qrCookie);
        } catch (Exception e) {
            logger.info(e.toString());
            StackTraceElement[] stackTraceElements = e.getStackTrace();
            for (StackTraceElement stackTraceElement : stackTraceElements) {
                logger.error(stackTraceElement.toString());
            }
        } finally {
            try {
                httpGet.disconnect();
            } catch (RequestNotExecutedException e) {
                logger.info(e.toString());
                StackTraceElement[] stackTraceElements = e.getStackTrace();
                for (StackTraceElement stackTraceElement : stackTraceElements) {
                    logger.error(stackTraceElement.toString());
                }
            }
        }
        //如果没有二维码cookie,抛出异常
        if (Objects.isNull(qrCookie)) {
            throw new NullQrCookieException();
        }
        //弹出二维码图片
        qrPopupBox = new QrPopupBox(icon, "登录QQ群官网");
        executorService.submit(qrPopupBox);

    }
}
